package com.own.business.pay.core.util;

import com.own.business.pay.common.constant.ConstantPay;
import com.own.business.pay.common.em.PayEnum;
import com.own.business.pay.common.exception.PayException;
import com.own.business.pay.core.model.PayOrderModel;
import com.own.business.pay.core.model.PayResultModel;
import com.own.business.pay.core.model.RefundOrderModel;
import com.own.business.pay.core.service.BillHistoryService;
import com.own.business.pay.entity.po.BillHistory;
import com.own.component.common.util.executor.ExecutorUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * UnitePayUtil
 *
 * @author chenxueli
 * @date 2023-07-13 14:30:00
 */
@Slf4j
@Component
public class UnitePayUtil {

    @Resource
    private BillHistoryService billHistoryService;
    @Resource
    private UnitePayRegisterUtil unitePayRegisterUtil;
    @Resource
    private ExecutorUtil executorUtil;

    /**
     * 创建订单（支付）
     *
     * @param method 方式渠道（wechat,alipay,wallet/balance）
     * @param type   支付类型（手机移动支付，二维码扫码支付）
     * @param model  支付订单
     * @return 支付凭证
     * @see com.own.business.pay.common.em.PayEnum.Method 支付方式信息
     * @see com.own.business.pay.common.em.PayEnum.Type 支付类型信息
     */
    @Transactional(rollbackFor = Exception.class)
    public PayResultModel createOrderPay(String method, PayEnum.Type type, PayOrderModel model) {
        return createOrderPay(PayEnum.getPayMethod(method), type, model);
    }

    /**
     * 创建订单（支付）
     *
     * @param method 方式渠道（wechat,alipay,wallet/balance）
     * @param type   支付类型（手机移动支付，二维码扫码支付）
     * @param model  支付订单
     * @return 支付凭证
     * @see com.own.business.pay.common.em.PayEnum.Method 支付方式信息
     * @see com.own.business.pay.common.em.PayEnum.Type 支付类型信息
     */
    @Transactional(rollbackFor = Exception.class)
    public PayResultModel createOrderPay(PayEnum.Method method, PayEnum.Type type, PayOrderModel model) {
        executorUtil.execute(() -> billHistoryService.initExpenditure(method, model.getTradeNo(), model));
        return unitePayRegisterUtil.getPayService(method.getType()).pay(type, model);
    }

    /**
     * 创建订单（提现）
     *
     * @param method 方式渠道（wechat,alipay,wallet/balance）
     * @param model  支付订单
     * @see com.own.business.pay.common.em.PayEnum.Method 支付方式信息
     * @see com.own.business.pay.common.em.PayEnum.Type 支付类型信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void createOrderIncome(String method, PayOrderModel model) {
        createOrderIncome(PayEnum.getPayMethod(method), model);
    }

    /**
     * 创建订单（收入）
     *
     * @param method 方式渠道（wechat,alipay,wallet/balance）
     * @param model  支付订单
     * @see com.own.business.pay.common.em.PayEnum.Method 支付方式信息
     * @see com.own.business.pay.common.em.PayEnum.Type 支付类型信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void createOrderIncome(PayEnum.Method method, PayOrderModel model) {
        billHistoryService.initIncome(method, model.getTradeNo(), model);
        unitePayRegisterUtil.getPayService(method.getType()).income(model);
    }

    /**
     * 查询订单
     *
     * @param outTradeNo 商户订单号
     * @return 账单信息
     */
    @Transactional(rollbackFor = Exception.class)
    public BillHistory queryPay(String outTradeNo) {
        return billHistoryService.getByTradeNo(outTradeNo);
    }

    /**
     * 查询订单
     *
     * @param method     方式渠道（wechat,alipay,wallet/balance）
     * @param outTradeNo 商户订单号
     * @return 账单信息
     * @see com.own.business.pay.common.em.PayEnum.Method 支付方式信息
     */
    @Transactional(rollbackFor = Exception.class)
    public BillHistory queryPay(String method, String outTradeNo) {
        return queryPay(PayEnum.getPayMethod(method), outTradeNo);
    }

    /**
     * 查询订单
     *
     * @param method     方式渠道（wechat,alipay,wallet/balance）
     * @param outTradeNo 商户订单号
     * @return 账单信息
     * @see com.own.business.pay.common.em.PayEnum.Method 支付方式信息
     */
    @Transactional(rollbackFor = Exception.class)
    public BillHistory queryPay(PayEnum.Method method, String outTradeNo) {
        // 查询对应的订单是否完成
        var bill = billHistoryService.getByTradeNo(outTradeNo);
        if (bill == null) {
            throw new PayException("支付单号不存在");
        }
        if (ConstantPay.Status.COMPLETE_SUCCESS == bill.getStatus()) {
            return bill;
        }
        return unitePayRegisterUtil.getPayService(method.getType()).query(outTradeNo);
    }

    /**
     * 申请退款
     *
     * @param method     方式渠道（wechat,alipay,wallet/balance）
     * @param outTradeNo 商户订单号
     * @param model      支付订单
     * @see com.own.business.pay.common.em.PayEnum.Method 支付方式信息
     * @see com.own.business.pay.common.em.PayEnum.Type 支付类型信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void createOrderRefund(String method, String outTradeNo, RefundOrderModel model) {
        createOrderRefund(PayEnum.getPayMethod(method), outTradeNo, model);
    }

    /**
     * 申请退款
     *
     * @param method     方式渠道（wechat,alipay,wallet/balance）
     * @param outTradeNo 商户订单号
     * @param model      支付订单
     * @see com.own.business.pay.common.em.PayEnum.Method 支付方式信息
     * @see com.own.business.pay.common.em.PayEnum.Type 支付类型信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void createOrderRefund(PayEnum.Method method, String outTradeNo, RefundOrderModel model) {
        // 查询原账单
        var bill = billHistoryService.getByTradeNo(outTradeNo);
        if (bill == null) {
            throw new PayException("支付单号不存在");
        }
        // 订单类型
        if (ConstantPay.Type.PAY != bill.getType()) {
            throw new PayException("当前订单类型不支持退款");
        }
        // 将原有的支付总金额放入退款金额中
        model.setTotal(bill.getTotalAmount());
        // 订单状态
        switch (bill.getStatus()) {
            case ConstantPay.Status.COMPLETE_SUCCESS -> {
                billHistoryService.initRefund(method, outTradeNo, model);
                unitePayRegisterUtil.getPayService(method.getType()).refund(outTradeNo, model);
            }
            case ConstantPay.Status.NEW_BUILT -> throw new PayException("订单未支付");
            case ConstantPay.Status.COMPLETE_CLOSE -> throw new PayException("订单关闭，未支付");
            case ConstantPay.Status.COMPLETE_TIMEOUT -> throw new PayException("订单超时，未支付");
            default -> throw new PayException("订单异常，未支付");
        }
    }

    /**
     * 查询退款订单
     *
     * @param outRefundNo 商户退款订单号
     * @return 账单信息
     */
    @Transactional(rollbackFor = Exception.class)
    public BillHistory queryRefund(String outRefundNo) {
        return billHistoryService.getByRefundNo(outRefundNo);
    }

    /**
     * 查询退款订单
     *
     * @param method      方式渠道（wechat,alipay,wallet/balance）
     * @param outTradeNo  商户订单号
     * @param outRefundNo 商户退款订单号
     * @return 账单信息
     * @see com.own.business.pay.common.em.PayEnum.Method 支付方式信息
     */
    @Transactional(rollbackFor = Exception.class)
    public BillHistory queryRefund(String method, String outTradeNo, String outRefundNo) {
        return queryRefund(PayEnum.getPayMethod(method), outTradeNo, outRefundNo);
    }

    /**
     * 查询退款订单
     *
     * @param method      方式渠道（wechat,alipay,wallet/balance）
     * @param outTradeNo  商户订单号
     * @param outRefundNo 商户退款订单号
     * @return 账单信息
     * @see com.own.business.pay.common.em.PayEnum.Method 支付方式信息
     */
    @Transactional(rollbackFor = Exception.class)
    public BillHistory queryRefund(PayEnum.Method method, String outTradeNo, String outRefundNo) {
        // 查询对应的订单是否完成
        var bill = billHistoryService.getByRefundNo(outRefundNo);
        if (bill == null) {
            throw new PayException("退款单号不存在");
        }
        if (ConstantPay.Status.COMPLETE_SUCCESS == bill.getStatus()) {
            return bill;
        }
        return unitePayRegisterUtil.getPayService(method.getType()).queryRefund(outTradeNo, outRefundNo);
    }

    /**
     * 关闭订单
     *
     * @param method      方式渠道（wechat,alipay,wallet/balance）
     * @param outRefundNo 商户退款订单号
     * @see com.own.business.pay.common.em.PayEnum.Method 支付方式信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void close(String method, String outRefundNo) {
        close(PayEnum.getPayMethod(method), outRefundNo);
    }

    /**
     * 关闭订单
     *
     * @param method      方式渠道（wechat,alipay,wallet/balance）
     * @param outRefundNo 商户退款订单号
     * @see com.own.business.pay.common.em.PayEnum.Method 支付方式信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void close(PayEnum.Method method, String outRefundNo) {
        unitePayRegisterUtil.getPayService(method.getType()).close(outRefundNo);
    }

}
